/* Bento Studio / 2012 / Uniflow / v1.1a
 *
 * Uniflow is an Unity clone of a well-known 3D gallery UI.
 *
 * UniflowUtils:
 * This component contains math utils used by Uniflow.
 *
 * v1.0 - Initial Release
 * v1.1 - Added fully working zoom, handlers. Fixed weird zoom rotation effect (by computing shortest rotation).
 * v1.1a - Reuploading to Unity Asset Store...
 */

using UnityEngine;
using System.Collections;

public static class UniflowUtils
{

	// Computes camera Horizontal Field of View (in radians)
	public static float HorizontalFOV( Camera a_rCamera )
	{
		float fHalfVerticalFOV = a_rCamera.fieldOfView * 0.5f;
		float fTanVerticalFOV = Mathf.Tan( fHalfVerticalFOV * Mathf.Deg2Rad );
		
		return 2.0f * Mathf.Atan( a_rCamera.aspect * fTanVerticalFOV );
	}

	// Computes main camera Horizontal Field of view (in radians)
	public static float HorizontalFOV( )
	{
		return HorizontalFOV( Camera.mainCamera );
	}

	// Computes main camera Horizontal Field of View (in degrees)
	public static float HorizontalFOVDeg( )
	{
		return Mathf.Rad2Deg * HorizontalFOV( Camera.mainCamera );
	}

	// Computes the camera frustum width at a given distance
	public static float CameraFrustumWidthAtDistance( Camera a_rCamera, float a_fDistanceFromCamera )
	{
		// Computes size from D = length / tan( FOV / 2 ) formula
		// => length = D * tan( FOV / 2 )
		float fHorizontalFOV = 0.5f * HorizontalFOV( a_rCamera );
		float fTanHorizontalFOV = Mathf.Tan( fHorizontalFOV );

		// In this case, because we got length from pivot point, it's only the half-length of the mesh
		// So, we need to multiply by 2 to get the "full" length
		return 2.0f * fTanHorizontalFOV * a_fDistanceFromCamera;
	}

	// Computes the camera frustum height at a given distance
	public static float CameraFrustumHeightAtDistance( Camera a_rCamera, float a_fDistanceFromCamera )
	{
		// Computes size from D = length / tan( FOV / 2 ) formula
		// => length = D * tan( FOV / 2 )
		float fVerticalFOV = a_rCamera.fieldOfView * 0.5f;
		float fTanVerticalFOV = Mathf.Tan( Mathf.Deg2Rad * fVerticalFOV );

		// In this case, because we got length from pivot point, it's only the half-length of the mesh
		// So, we need to multiply by 2 to get the "full" length
		return 2.0f * fTanVerticalFOV * a_fDistanceFromCamera;	
	}

	// Computes the *main* camera frustrum height at a given distance
	public static float CameraFrustumHeightAtDistance( float a_fDistanceFromMainCamera )
	{
		return CameraFrustumHeightAtDistance( Camera.mainCamera, a_fDistanceFromMainCamera );	
	}

	// Computes the *main* camera frustum width at a given distance
	public static float CameraFrustumWidthAtDistance( float a_fDistanceFromMainCamera )
	{
		return CameraFrustumWidthAtDistance( Camera.mainCamera, a_fDistanceFromMainCamera );
	}

	// Computes the distance to a camera from a frustum width 
	public static float DistanceToCameraFromFrustumWidth( Camera a_rCamera, float a_fFrustumWidth )
	{
		float fHorizontalFOV = HorizontalFOV( a_rCamera ) * 0.5f;
		float fTanHorizontalFOV = Mathf.Tan( fHorizontalFOV );
		return a_fFrustumWidth / fTanHorizontalFOV;
	}

	// Computes the distance to a camera from a frustum height
	public static float DistanceToCameraFromFrustumHeight( Camera a_rCamera, float a_fFrustumHeight )
	{
		float fVerticalFOV = a_rCamera.fieldOfView * 0.5f;
		float fTanVerticalFOV = Mathf.Tan( Mathf.Deg2Rad * fVerticalFOV );
		return a_fFrustumHeight / fTanVerticalFOV;
	}

	// Computes the shortest rotation from given euler angles
	public static Vector3 ShortestEulerAnglesRotation( Vector3 a_f3EulerAngles )
	{
		if( a_f3EulerAngles.x > 180.0f )
		{
			a_f3EulerAngles.x = a_f3EulerAngles.x - 360.0f;
		}

		if( a_f3EulerAngles.y > 180.0f )
		{
			a_f3EulerAngles.y = a_f3EulerAngles.y - 360.0f;
		}

		if( a_f3EulerAngles.z > 180.0f )
		{
			a_f3EulerAngles.z = a_f3EulerAngles.z - 360.0f;
		}

		return a_f3EulerAngles;
	}
}
